package com.hockeo.client.ui.base.tree;

import java.util.List;

import com.extjs.gxt.ui.client.data.BaseTreeLoader;
import com.extjs.gxt.ui.client.data.BeanModel;
import com.extjs.gxt.ui.client.data.ModelIconProvider;
import com.extjs.gxt.ui.client.data.ModelStringProvider;
import com.extjs.gxt.ui.client.data.RpcProxy;
import com.extjs.gxt.ui.client.data.TreeLoader;
import com.extjs.gxt.ui.client.store.TreeStore;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.treepanel.TreePanel;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AbstractImagePrototype;

/**
 * Generic tree widget.
 *
 * @version $Id$
 * @author jjanke
 */
public class VHTree extends LayoutContainer
{
  private final IVHTreeConfig               d_cfg;
  private final TreePanel<BeanModel>        d_tree;
  private final TreeStore<BeanModel>        d_store;
  private final TreeLoader<BeanModel>       d_loader;
  private final RpcProxy<List<?>> d_proxy;

  public VHTree( IVHTreeConfig cfg )
  {
    d_cfg = cfg;
    d_proxy = createProxy();
    d_loader = createLoader( d_proxy );
    d_store = createStore( d_loader );
    d_tree = createTree( d_store );

    d_tree.setIconProvider( createIconProvider() );
    d_tree.setLabelProvider( createLabelProvider() );

    setLayout( new FitLayout() );
    setBorders( false );
    setLayoutOnChange( true );
    add( d_tree );
  }

  public IVHTreeConfig getConfig()
  {
    return d_cfg;
  }

  public TreeStore<BeanModel> getStore()
  {
    return d_store;
  }

  protected RpcProxy<List<?>> createProxy()
  {
    RpcProxy<List<?>> proxy = new RpcProxy<List<?>>()
    {
      @Override
      protected void load( Object objParent, AsyncCallback<List<?>> callback )
      {
        if ( objParent == null )
          d_cfg.loadRoots( callback );
        else
          d_cfg.loadChildNodes( (BeanModel) objParent, callback );
      }
    };

    return proxy;
  }

  protected TreeLoader<BeanModel> createLoader( RpcProxy<List<?>> proxy )
  {
    VHTreeBeanModelReader reader = new VHTreeBeanModelReader();

    // using a separate bean factory for each item in the list is required as we expect
    // heterogenous structures (different types of objects in the tree)
    //
    reader.setFactoryForEachBean( true );

    TreeLoader<BeanModel> loader = new BaseTreeLoader<BeanModel>( proxy, reader )
    {
      @Override
      public boolean hasChildren( BeanModel parent )
      {
        if ( parent == null )
          return true;

        return d_cfg.hasChildren( parent );
      }
    };

    return loader;
  }

  protected TreeStore<BeanModel> createStore( TreeLoader<BeanModel> loader )
  {
    return new TreeStore<BeanModel>( loader );
  }

  protected TreePanel<BeanModel> createTree( TreeStore<BeanModel> store )
  {
    return new TreePanel<BeanModel>( store );
  }

  protected ModelIconProvider<BeanModel> createIconProvider()
  {
    return new ModelIconProvider<BeanModel>()
    {
      @Override
      public AbstractImagePrototype getIcon( BeanModel model )
      {
        return d_cfg.getIcon( model );
      }
    };
  }

  protected ModelStringProvider<BeanModel> createLabelProvider()
  {
    return new ModelStringProvider<BeanModel>()
    {
      @Override
      public String getStringValue( BeanModel model, String strProperty )
      {
        return d_cfg.getLabel( model );
      }
    };
  }
}
